package com.igo.util;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateField;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.igo.domain.datacollection.devicedata.DeviceDataCalcd;
import com.igo.domain.datacollection.devicedata.DeviceInfo;
import com.igo.domain.datacollection.devicedata.FlatCarData;
import com.igo.domain.datacollection.devicedata.GantryCraneCaData;
import com.igo.enums.devicedata.CalcdTypeEnum;
import com.igo.enums.devicedata.GantryCraneTypeEnum;
import com.igo.enums.devicedata.LoadTypeEnum;
import com.igo.enums.devicedata.LoadValidEnum;
import com.igo.mapper.devicedata.FlatCarDataMapper;
import com.igo.service.devicedata.DeviceDataCalcdService;
import com.igo.service.devicedata.FlatCarDataService;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.stream.Collectors;

@Component
public class DeviceDataCalculateFlatCar {

    private ExecutorService es = Executors.newFixedThreadPool(2000);
    @Resource
    private FlatCarDataService flatCarDataService;

    @Resource
    private DeviceDataCalcdService deviceDataCalcdService;
    @Resource
    private FlatCarDataMapper flatCarDataMapper;


    private Date startTime;

    private Date endTime;


    public void calculateData(){
        String strStartTime = "2024-12-01 00:00:00";
        Date start = DateUtil.parse(strStartTime);
        String strEndTime = "2024-12-27 23:59:59";
        Date end = DateUtil.parse(strEndTime);
        while(start.compareTo(end)<=0){
            endTime = DateUtil.offset(start, DateField.DAY_OF_MONTH, 1);
            endTime=DateUtil.offset(endTime, DateField.SECOND, -1);
            calculateFlatCarData(start,endTime);
            start=DateUtil.offset(endTime, DateField.SECOND, 1);
        }

    }

    //计算数据
    //平板车任务明细
//    @Transactional(rollbackFor = Exception.class)
    public void calculateFlatCarData(Date strStartTime, Date strEndTime){
        //处理时间
//        calculateTime(strStartTime, strEndTime);
        Comparator<FlatCarData> comparator = Comparator.comparing(FlatCarData::getDataTime,Comparator.naturalOrder());
        List<FlatCarData> updateFlatCarDatas = new ArrayList<>();
        List<FlatCarData> originFlatCarDataListData = flatCarDataMapper
                .selectJoinList(FlatCarData.class,new MPJLambdaWrapper<FlatCarData>()
                        .selectAll(FlatCarData.class)
                        .eq(FlatCarData::getRunningState,"1")
                        .ge(FlatCarData::getCreateTime,strStartTime).le(FlatCarData::getCreateTime, strEndTime)
                        .innerJoin(DeviceInfo.class, DeviceInfo::getDeviceNo, FlatCarData::getDeviceNo)
                        .selectAs(DeviceInfo::getProductId,FlatCarData::getProductId)
                        .selectAs(DeviceInfo::getOilHeight,FlatCarData::getOilHeight)
                        .selectAs(DeviceInfo::getOilLength,FlatCarData::getOilLength)
                        .selectAs(DeviceInfo::getOilWidth,FlatCarData::getOilWidth)
                        .selectAs(DeviceInfo::getLoadCapacity,FlatCarData::getMaxLoadCapacity)
                        .eq(DeviceInfo::getProductId,"2")
                        .orderByAsc(FlatCarData::getDataTime));
        List<FlatCarData> originFlatCarDataList = new ArrayList<>();
        for (int i = 0; i < originFlatCarDataListData.size(); i+=5) {
            originFlatCarDataList.add(originFlatCarDataListData.get(i));
        }
//        按载重计算数据
        //设备编号
        Set<String> deviceNos = originFlatCarDataList.stream().map(FlatCarData::getDeviceNo).collect(Collectors.toSet());
        List<DeviceDataCalcd> deviceDataCalcds = new ArrayList<>();
        List<List<FlatCarData>> flatCarTaskList=new ArrayList<>();
        deviceNos.stream().forEach(deviceNo->{
            List<FlatCarData> flatCarDataList = originFlatCarDataList.stream().sorted(comparator)
                    .filter(flatCarData -> flatCarData.getDeviceNo().equals(deviceNo))
                    .collect(Collectors.toList());
            //第一种按照载重来计算
            //过滤载重的错误数据
            for (int i = flatCarDataList.size()-1; i>=0; i--) {
                try {
                    if (StringUtils.isBlank(flatCarDataList.get(i).getLoadCapacity())){
                        flatCarDataList.get(i).setLoadCapacity("0");
                    }
                    if (flatCarDataList.get(i).getLoadCapacity().startsWith("F")) {
                        String loadCapacity = flatCarDataList.get(i).getLoadCapacity();
                        loadCapacity = loadCapacity.substring(1);
                        flatCarDataList.get(i).setLoadCapacity(loadCapacity);
                    }
                    if (flatCarDataList.get(i).getLoadCapacity().startsWith("+")){
                        String loadCapacity = (new BigDecimal(flatCarDataList.get(i).getLoadCapacity().substring(1))
                                .subtract(new BigDecimal("4"))).multiply(new BigDecimal("25")).toString();
                        flatCarDataList.get(i).setLoadCapacity(loadCapacity);
                    }
                    new BigDecimal(flatCarDataList.get(i).getLoadCapacity());
                }catch (NumberFormatException e){
                    flatCarDataList.get(i).setLoadCapacity("0");
                }
                //过滤载重过大的错误数据 如果数据超过平板车最大值的150%为错误数据  废弃
//                 if (new BigDecimal(flatCarDataList.get(i).getLoadCapacity())
//                        .compareTo(new BigDecimal(flatCarDataList.get(i).getMaxLoadCapacity()).multiply(new BigDecimal("1.5")))>=0){
//                    flatCarDataList.get(i).setLoadCapacity("0");
//                }
            }
            //移动位 标记位
            int i = 0,k=0;
            int j = i+1;
            BigDecimal preIndex=new BigDecimal("0");
            BigDecimal seqIndex=new BigDecimal("0");
            for (; i <flatCarDataList.size()-1 && j<flatCarDataList.size(); i++,j++) {
                preIndex = new BigDecimal(flatCarDataList.get(i).getLoadCapacity());
                seqIndex = new BigDecimal(flatCarDataList.get(j).getLoadCapacity());
                //不相等记录之前的实时数据生成任务
                if ((preIndex.compareTo(new BigDecimal("0"))==0 && seqIndex.compareTo(new BigDecimal("0"))>0)
                        ||(preIndex.compareTo(new BigDecimal("0"))>0 && seqIndex.compareTo(new BigDecimal("0"))==0)) {
                    //不相等
                    //构建任务明细
                    List<FlatCarData> flatCarTask =new ArrayList<>();
                    //第一行数据不等于第二行数据
                    if (k==i){
                        FlatCarData flatCarData = flatCarDataList.get(k);
                        flatCarTask.add(flatCarData);
                    }else {
                        for (int l = k; l <j; l++) {
                            flatCarTask.add(flatCarDataList.get(l));
                        }
                    }
                    flatCarTaskList.add(flatCarTask);

                    //求和项
                    //处理经纬度数据
                    //如果任务明细中间隔超过1小时的算离线
                    k=j;
                }
            }
            //计算加油任务
            List<DeviceDataCalcd> addOilQuantityCalcds = getAddOilQuantityCalcd(flatCarDataList);
            //生成加油任务
            deviceDataCalcds.addAll(addOilQuantityCalcds);

            //遗留数据重新计算
            List<FlatCarData> flatCarTask = flatCarDataList.subList(k,j);
            flatCarTaskList.add(flatCarTask);
        });
        if(CollectionUtil.isNotEmpty(flatCarTaskList)){
            flatCarTaskList.stream().forEach(flatCarDataList->{
                splitData(flatCarDataList).stream().filter(CollectionUtil::isNotEmpty).forEach(flatCarData -> {
                    DeviceDataCalcd flatCarDeviceDataCalcds = getFlatCarDeviceDataCalcds(flatCarData);
                    deviceDataCalcds.add(flatCarDeviceDataCalcds);
                    updateFlatCarDatas.addAll(flatCarData);
                });
            });
        }
        if (CollectionUtil.isNotEmpty(updateFlatCarDatas)) {
            flatCarDataService.updateBatchById(updateFlatCarDatas);
        }

        if(CollectionUtil.isNotEmpty(deviceDataCalcds)){
            List<DeviceDataCalcd> insertList = deviceDataCalcds.stream().filter(deviceDataCalcd -> deviceDataCalcd != null).collect(Collectors.toList());
            deviceDataCalcdService.saveBatch(insertList);
        }
    }

    List<List<FlatCarData>> splitData(List<FlatCarData> flatCarDataList){
        List<List<FlatCarData>> flatCarTaskList=new ArrayList<>();
        if (flatCarDataList.size()!=1) {
        //标志位
            int k = 0;
            int i = 0;
            int j=i+1;
            boolean flag = true;
            for (; i <flatCarDataList.size()-1; i++,j++) {
                long time = flatCarDataList.get(j).getDataTime().getTime()-flatCarDataList.get(i).getDataTime().getTime();
                if (new BigDecimal(time).divide(new BigDecimal("1000"), 1, RoundingMode.HALF_UP)
                        .divide(new BigDecimal("60"), 1, RoundingMode.HALF_UP).compareTo(new BigDecimal("60"))>=1) {
                    flag=false;
                    List<FlatCarData> lists = new ArrayList<>();
                    for (int l = k; l <j; l++) {
                        lists.add(flatCarDataList.get(l));
                    }
                    flatCarTaskList.add(lists);
                    k=j;
                }

            }
            if (flag){
                //没有发生分割
                flatCarTaskList.add(flatCarDataList);
            }else {
                //分割最后数据
                flatCarTaskList.add(flatCarDataList.subList(k,j));
            }
        }
        return flatCarTaskList;
    }


    public List<DeviceDataCalcd> getAddOilQuantityCalcd(List<FlatCarData> flatCarDataList){
        List<DeviceDataCalcd> addOilQuantityCalcds = new ArrayList<DeviceDataCalcd>();
        List<Integer> removeList =new ArrayList<>();
        for (int i = flatCarDataList.size()-1; i>=0; i--) {
            try {
                BigDecimal oilQuantity = new BigDecimal(flatCarDataList.get(i).getOilQuantity());
            }catch (Exception e){
                removeList.add(i);
            }
        }
        for (int i = 0,j=i+1; i <flatCarDataList.size()-1 && j<flatCarDataList.size(); i++,j++) {
            if (removeList.contains(i) || removeList.contains(j)) {
                continue;
            }
            BigDecimal preOilQuantity = new BigDecimal(flatCarDataList.get(i).getOilQuantity());
            BigDecimal seqOilQuantity = new BigDecimal(flatCarDataList.get(j).getOilQuantity());
            if (preOilQuantity.compareTo(seqOilQuantity)==-1) {
                DeviceDataCalcd deviceDataCalcd = new DeviceDataCalcd();
                //设备编号
                deviceDataCalcd.setDeviceNo(flatCarDataList.get(j).getDeviceNo());
                //加油量
                deviceDataCalcd.setAddOilQuantity(seqOilQuantity.subtract(preOilQuantity));
                deviceDataCalcd.setCalcdType(CalcdTypeEnum.OILING.getValue());
                deviceDataCalcd.setStartTime(DateUtil.format(flatCarDataList.get(i).getDataTime(), "yyyy-MM-dd hh:mm:ss"));
                deviceDataCalcd.setEndTime(DateUtil.format(flatCarDataList.get(j).getDataTime(), "yyyy-MM-dd hh:mm:ss"));
                deviceDataCalcd.setCreateTime(DateUtil.format(flatCarDataList.get(j).getDataTime(), "yyyy-MM-dd hh:mm:ss"));
                addOilQuantityCalcds.add(deviceDataCalcd);
                //生成加油任务数据
            }
        }
        return addOilQuantityCalcds;
    }
    /**
     * 计算任务数据
     * @param flatCarTask
     * @return
     */
    public DeviceDataCalcd getFlatCarDeviceDataCalcds(List<FlatCarData> flatCarTask){
        //不相等
        //构建任务明细
        DeviceDataCalcd deviceDataCalcd = new DeviceDataCalcd();
        //计算任务数据
        //求和项
        //处理经纬度数据
        List<FlatCarData> location = flatCarTask.stream()
                .filter(flatCarData -> StringUtils.isNotBlank(flatCarData.getLatitude())
                        && StringUtils.isNotBlank(flatCarData.getLongitude())).collect(Collectors.toList());
        //过滤错误定位
        List<FlatCarData> strictlyLocation = StrictGpsFilter.filterStrictly(location);
        BigDecimal mileage = calculateDistance(strictlyLocation, null);
        //油耗
        List<String> oilQuantityList = flatCarTask.stream()
                .filter(flatCarData -> StringUtils.isNotBlank(flatCarData.getOilQuantity()))
                .map(FlatCarData::getOilQuantity).collect(Collectors.toList());
        //计算油耗
        BigDecimal oilQuantity = getOilQuantity(oilQuantityList, flatCarTask.get(0));
        //时长
        long l = flatCarTask.get(flatCarTask.size()-1).getDataTime().getTime() - flatCarTask.get(0).getDataTime().getTime();
        BigDecimal loadTimeValue = new BigDecimal(l).divide(new BigDecimal("1000"), 1, RoundingMode.HALF_UP);
        //载重
        //取实时数据中平均值
        BigDecimal loadCapacity = calculateAverage(flatCarTask.stream().map(FlatCarData::getLoadCapacity).map(BigDecimal::new).collect(Collectors.toList()));

//                    生成任务明细
        if (loadCapacity.compareTo(new BigDecimal("0"))==1){
            //是否是载重状态
            deviceDataCalcd.setCalcdType(CalcdTypeEnum.LOAD.getValue());
            //判断载重类型
            if (loadCapacity.compareTo(new BigDecimal("30"))==1){
                //大负载
                deviceDataCalcd.setLoadType(LoadTypeEnum.HEAVYLOAD.getValue());
            }else {
                //小负载
                deviceDataCalcd.setLoadType(LoadTypeEnum.SMALLLOAD.getValue());
            }
            //判断任务有效性
            if (loadTimeValue.divide(new BigDecimal("60"), 1, RoundingMode.HALF_UP).compareTo(new BigDecimal("15"))==1){
                //有效任务
                deviceDataCalcd.setLoadValid(LoadValidEnum.VALID.getValue());
            }else if (loadTimeValue.divide(new BigDecimal("60"), 1, RoundingMode.HALF_UP).compareTo(new BigDecimal("15"))<=0){
                //无效任务
                deviceDataCalcd.setLoadValid(LoadValidEnum.INVALID.getValue());
            }
            //设备编号
            deviceDataCalcd.setDeviceNo(flatCarTask.get(0).getDeviceNo());
            //任务开始时间
            deviceDataCalcd.setStartTime(DateUtil.formatDateTime(flatCarTask.get(0).getDataTime()));
            deviceDataCalcd.setCreateTime(DateUtil.formatDateTime(flatCarTask.get(0).getDataTime()));
            //任务结束时间
            deviceDataCalcd.setEndTime(DateUtil.formatDateTime(flatCarTask.get(flatCarTask.size()-1).getDataTime()));
            //载重重量
            deviceDataCalcd.setLoadCapacity(loadCapacity);
            //最大载重重量
            BigDecimal maxLoadCapacity = calculateMax(flatCarTask.stream().map(FlatCarData::getLoadCapacity).map(BigDecimal::new).collect(Collectors.toList()));
            deviceDataCalcd.setLoadCapacityMax(maxLoadCapacity);
            //平均载重
            deviceDataCalcd.setLoadCapacityAvg(loadCapacity);
            //油耗
            deviceDataCalcd.setOilConsumption(oilQuantity);
            //里程
            //任务所经过的经纬度
            List<String> positions = new ArrayList<>();
            //过滤错误定位
            strictlyLocation.stream().forEach(flatCarData->{
                String position=flatCarData.getLongitude()+","+flatCarData.getLatitude();
                positions.add(position);
            });
            deviceDataCalcd.setLatLongList(positions);
            deviceDataCalcd.setMileage(mileage);
            //任务时长 单位:s
            deviceDataCalcd.setLoadTime(loadTimeValue);
            //车速
            //最大车速
            //平均车速
            //任务类型
            deviceDataCalcd.setGantryCraneType(GantryCraneTypeEnum.FLATCARTASK.getValue());
        }else if (loadCapacity.compareTo(new BigDecimal("0"))==0){
            //是否是载重状态
            deviceDataCalcd.setCalcdType(CalcdTypeEnum.NOLOAD.getValue());
            //设备编号
            deviceDataCalcd.setDeviceNo(flatCarTask.get(0).getDeviceNo());
            //任务开始时间
            deviceDataCalcd.setStartTime(DateUtil.formatDateTime(flatCarTask.get(0).getDataTime()));
            deviceDataCalcd.setCreateTime(DateUtil.formatDateTime(flatCarTask.get(0).getDataTime()));
            //任务结束时间
            deviceDataCalcd.setEndTime(DateUtil.formatDateTime(flatCarTask.get(flatCarTask.size()-1).getDataTime()));
            //载重重量
            deviceDataCalcd.setLoadCapacity(loadCapacity);
            //油耗
            deviceDataCalcd.setOilConsumption(oilQuantity);
            //任务所经过的经纬度
            List<String> positions = new ArrayList<>();
            //过滤错误定位
            strictlyLocation.stream().forEach(flatCarData->{
                String position=flatCarData.getLongitude()+","+flatCarData.getLatitude();
                positions.add(position);
            });
            deviceDataCalcd.setLatLongList(positions);
            //里程
            deviceDataCalcd.setMileage(mileage);
            //任务时长 单位:s
            deviceDataCalcd.setLoadTime(loadTimeValue);
            //任务类型
            deviceDataCalcd.setGantryCraneType(GantryCraneTypeEnum.FLATCARTASK.getValue());
        }else {
        return null;
    }
        //绑定原始数据和任务数据关系
        deviceDataCalcd.setCalcdNo(IdUtil.simpleUUID());
        flatCarTask.stream().forEach(flatCarData -> {
            flatCarData.setCalcdNo(deviceDataCalcd.getCalcdNo());
        });
        return deviceDataCalcd;
    }


    //里程
    public static BigDecimal calculateDistance(List<FlatCarData> flatCarDataList,List<GantryCraneCaData> gantryCraneCaDataList) {

        BigDecimal sum = new BigDecimal("0");
        if (CollectionUtil.isNotEmpty(flatCarDataList)){

            for (int i = 0,j=i+1; i <flatCarDataList.size()-1 && j<flatCarDataList.size(); i++,j++) {
                Double lat1 = Double.valueOf(flatCarDataList.get(i).getLatitude());
                Double lat2 = Double.valueOf(flatCarDataList.get(j).getLatitude());
                Double lon1 = Double.valueOf(flatCarDataList.get(i).getLongitude());
                Double lon2 = Double.valueOf(flatCarDataList.get(j).getLongitude());
                sum=sum.add(new BigDecimal(GeoUtils.getDistance(lon1,lat1,lon2,lat2)));
            }
        }

        if (CollectionUtil.isNotEmpty(gantryCraneCaDataList)){
            for (int i = 0,j=i+1; i <gantryCraneCaDataList.size()-1 && j<gantryCraneCaDataList.size(); i++,j++) {
                Double lat1 = Double.valueOf(gantryCraneCaDataList.get(i).getLatitude());
                Double lat2 = Double.valueOf(gantryCraneCaDataList.get(j).getLatitude());
                Double lon1 = Double.valueOf(gantryCraneCaDataList.get(i).getLongitude());
                Double lon2 = Double.valueOf(gantryCraneCaDataList.get(j).getLongitude());
                sum=sum.add(new BigDecimal(GeoUtils.getDistance(lon1,lat1,lon2,lat2)));
            }
        }

        return sum.divide(new BigDecimal("1000"), 6, RoundingMode.HALF_UP);
    }

//    此次任务油耗
    public BigDecimal getOilQuantity(List<String> oilQuantityList,FlatCarData flatCarData){

        for (int i = oilQuantityList.size()-1; i>=0; i--) {
            try {
                BigDecimal loadCapacity = new BigDecimal(oilQuantityList.get(i));
            }catch (Exception e){
                oilQuantityList.remove(i);
            }
        }
        BigDecimal sumOilQuantity = new BigDecimal("0");
        for (int i = 0,j=i+1; i <oilQuantityList.size()-1 && j<oilQuantityList.size(); i++,j++) {

            BigDecimal preOilQuantity = new BigDecimal(oilQuantityList.get(i));
            BigDecimal seqOilQuantity = new BigDecimal(oilQuantityList.get(j));
            if (preOilQuantity.compareTo(seqOilQuantity)==1
//                    &&  preOilQuantity.subtract(seqOilQuantity).compareTo(new BigDecimal("20"))==-1
            ) {
                sumOilQuantity=sumOilQuantity.add(preOilQuantity.subtract(seqOilQuantity));
            }
        }
        return sumOilQuantity;
    }

    public BigDecimal getAddOilQuantity(List<String> oilQuantityList){

        for (int i = oilQuantityList.size()-1; i>=0; i--) {
            try {
                BigDecimal oilQuantity = new BigDecimal(oilQuantityList.get(i));
            }catch (NumberFormatException e){
                oilQuantityList.remove(i);
            }
        }
        BigDecimal sumOilQuantity = new BigDecimal("0");
        for (int i = 0,j=i+1; i <oilQuantityList.size()-1 && j<oilQuantityList.size(); i++,j++) {

            BigDecimal preOilQuantity = new BigDecimal(oilQuantityList.get(i));
            BigDecimal seqOilQuantity = new BigDecimal(oilQuantityList.get(j));
            if (preOilQuantity.compareTo(seqOilQuantity)==-1) {
                sumOilQuantity=sumOilQuantity.add(seqOilQuantity.subtract(preOilQuantity));
            }
        }
        return sumOilQuantity;
    }


    //计算平均值
    public static BigDecimal calculateAverage(List<BigDecimal> numbers) {
        BigDecimal divide =new BigDecimal("0");
        if (CollectionUtil.isNotEmpty(numbers)) {
            ArrayList<BigDecimal> list = new ArrayList<>();
            numbers.stream().forEach(number->list.add(number));
            BigDecimal sum = list.stream().reduce(BigDecimal.ZERO, BigDecimal::add);
            divide = sum.divide(BigDecimal.valueOf(numbers.size()), 2, BigDecimal.ROUND_HALF_UP);
        }
        return divide;
    }

    //计算最大值
    public static BigDecimal calculateMax(List<BigDecimal> numbers) {
        BigDecimal max = Collections.max(numbers);
        return max;
    }



    public static void main(String[] args) {
    }

}
